package application;


import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

import javafx.collections.FXCollections;

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

import jeopardy.common.protocol.game.stats.ShowGameListReqMsg;
import jeopardy.common.protocol.game.stats.ShowGameListResMsg;
import jeopardy.common.protocol.game.stats.ShowUserRankingsReqMsg;
import jeopardy.common.protocol.game.stats.ShowUserRankingsResMsg;
import jeopardy.common.protocol.game.stats.UserScore;
import jeopardy.common.protocol.useraccount.UserAccountConsts;
import jeopardy.common.protocol.useraccount.UserAccountRequest;
import jeopardy.common.protocol.useraccount.UserAccountUtils;

public class PreGameScreenFetchData implements Runnable {

    public UserSession sessionU;
    public PreGameScreenSession sessionG;

    public String userName;
    public char[] passWord;
    public int authenticated;
    public int sockType = 2;
    public static List<String> myAvailableGames;
    
    public static int sleepExtent = 1000;
      
	private static int connected;
	
	public int loopCounter = 0;
	public int maxIteration = 10;

	String SERVER_IP; 
	static int SERVER_PORT;
	private static SSLSocket statSocket;
	public static byte[] returnCode;
	
    
    private String msg;
    

	public PreGameScreenFetchData()
    {
		authenticated = 0;
		connected = 0;
		passWord = null;
		userName = null;
		SERVER_IP = null;
		SERVER_PORT = -1;
		returnCode = new byte[UserAccountConsts.USERACCOUNT_MAX_RES_LEN];
		sessionU = UserSession.getInstance();
		sessionG = PreGameScreenSession.getInstance();	
    }
    
    /*
    * This methos is used to close socket
    */
    public static int closeSocket()
	{
			int ret = 0;
			try {
					statSocket.close();
			} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
			}
			if(statSocket.isClosed()) {
					ret = 1;
			}
			
			return ret;
	}
    
	/*
	 * This method is used to create socket to communicate with the server
	 */
	public static int createSocket(int type)
	{
		// byte[] returnCode = new byte[UserAccountConsts.USERACCOUNT_MAX_RES_LEN];
		switch(type) {
			
			case 1: SERVER_PORT = ClientConsts.SERVER_PORT_USER_ACCOUNT;
					break;
			case 2: SERVER_PORT = ClientConsts.SERVER_PORT_STATS;
					break;
			case 3: SERVER_PORT = ClientConsts.SERVER_PORT_GAME;
					break;
			default: SERVER_PORT = -9000;
					break;
		}
		try {
			SSLSocketFactory sslsocketfactory = ClientConsts.createSSLFactory();
			statSocket = (SSLSocket) sslsocketfactory.createSocket(
						ClientConsts.SERVER_IP, SERVER_PORT);
			connected = 1;
			return 0;
			
		} catch (Exception exception) {
			exception.printStackTrace();
			// System.out.println("PreGameScreenFetchData::createSocket - Failed to create socket");
			connected = 0;
	        return 1;
		}	
	}
	
	// Not necessary - redundant 
	public static void copyLists(List<String> destList)
	{
		destList = new ArrayList<String>(myAvailableGames);
		// System.out.println("FetchGameListAndStats::copyList - copying list");
		if(myAvailableGames.size() > 0) {
			for (int i=0; i < myAvailableGames.size(); i++) {
				String element = myAvailableGames.get(i);
				// System.out.println(element);
			}
		}
	}
	
	public void run() 
	{
		// Loop twenty times
		while( ((authenticated = sessionU.getStatus())== 0) && (loopCounter < maxIteration) ) { 
			try {
				// System.out.println("PreGameScreenFetchData::run - Logged in status is: " + sessionU.getStatus());
				// System.out.println("PreGameScreenFetchData::run -  Going back to sleep");
				Thread.sleep(sleepExtent);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			maxIteration++;
		}
		
		// The user is authenticated then retrieve the stats from the server
		if(authenticated == 1) {
			// System.out.println("PreGameScreenFetchData::run - Authenticated, connecting the server");
			
			createSocket(sockType);
			if(statSocket.isConnected()) {
				
				// System.out.println("PreGameScreenFetchData::run FetchGameListAndStats - connected to the server");
				// System.out.println("PreGameScreenFetchData::run - Retrieving Game list & player rankings");
				try {
					ShowGameListReqMsg newReq = new ShowGameListReqMsg(sessionU.userName, sessionU.password);
				
					ObjectOutputStream newOut = new ObjectOutputStream(statSocket.getOutputStream());
					newOut.writeObject(newReq);
					ObjectInputStream newIn = new ObjectInputStream(statSocket.getInputStream());
					ShowGameListResMsg response = (ShowGameListResMsg) newIn.readObject();
					
					String[] games = response.getWaiting();
					int counter = 0;
					for(String game : games) {
						sessionG.myAvailableGames.add(game);
						// System.out.println("Game retrieved is: "+counter+"The value is:"+game);
						counter++;
					}
				 
					// System.out.println("Number of available games: "+ ((PreGameScreenSession) myAvailableGames).getListLength());
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				closeSocket();
			}
			else {
				// System.out.println("Failed to create socket for retrieving available games to join");
			}

			
			// Re-open statistics socket
			createSocket(sockType);
			if(statSocket.isConnected()) {
				
				// Code for building player ranking
				// System.out.println("PreGameScreenFetchData::run - building playerStatsData");
				// sessionG.playerStatsData.addAll();
				sessionG = PreGameScreenSession.getInstance();
				try {
					// Create an object for requesting player ranking data
					ShowUserRankingsReqMsg newRankingReq = new ShowUserRankingsReqMsg(sessionU.userName, sessionU.password);
					
					//Create an outputstream for sending the request
					ObjectOutputStream newOutStream = new ObjectOutputStream(statSocket.getOutputStream());
					newOutStream.writeObject(newRankingReq);
					
					//Create an inputstream for reading the server response
					ObjectInputStream newInStream = new ObjectInputStream(statSocket.getInputStream());
					ShowUserRankingsResMsg newRankingRes = (ShowUserRankingsResMsg) newInStream.readObject();
					
					UserScore[] rankers = newRankingRes.getRankers();
					
					List<PreGameScreenPlayerRanking> tmpList = new LinkedList<PreGameScreenPlayerRanking>();
					
					for(UserScore ranker : rankers) {
						tmpList.add(new PreGameScreenPlayerRanking(ranker.getUserName(), ranker.getTotalScore()));
					}
					sessionG.playerStatsData = FXCollections.observableArrayList(tmpList);
				}catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				closeSocket();
				
				/* Code for statically building the data
				sessionG.playerStatsData = FXCollections.observableArrayList(
		    		new PreGameScreenPlayerRanking("Alex Tribeck", 100),
		    		new PreGameScreenPlayerRanking("Vanna White", 100),
		    		new PreGameScreenPlayerRanking("Jay Leno", 100),
		    		new PreGameScreenPlayerRanking("Geoge W. Bush", 23)
				);
				*/
			}
			else {
				// System.out.println("Failed to create socket for retrieving player rankings");
			}		
		//Print list of games
		// System.out.println("Printing list of games available");
		// sessionG.printList();

		}
		else {
			// System.out.println("The user has not authenticated yet");
		}
	
	}
}
	
